﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using GBlason.ViewModel;

namespace GBlason.Common.CustomCommand
{
    /// <summary>
    /// Override RoutedUiCommand to allow the application to handle the undo / redo behaviour for the command performed on the CoatOfArmsComponent's properties or children
    /// </summary>
    public abstract class CommandGeneric : RoutedCommand, INotifyPropertyChanged, ICloneable
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CommandGeneric"/> class.
        /// </summary>
        protected CommandGeneric()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CommandGeneric"/> class.
        /// </summary>
        /// <param name="text">The text used in this case as a Description.</param>
        /// <param name="ownerType">Type of the owner.</param>
        protected CommandGeneric(String text, Type ownerType)
            : base(text, ownerType)
        {
            Description = text;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CommandGeneric"/> class.
        /// </summary>
        /// <param name="text">The text. Used in this case as a description</param>
        /// <param name="ownerType">Type of the owner.</param>
        /// <param name="input">The input.</param>
        protected CommandGeneric(String text, Type ownerType, InputGestureCollection input)
            : base(text, ownerType, input)
        {
            Description = text;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CommandGeneric"/> class.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="ownerType">Type of the owner.</param>
        /// <param name="input">The input.</param>
        /// <param name="description">The description.</param>
        protected CommandGeneric(String text, Type ownerType, InputGestureCollection input, String description)
            : base(text, ownerType, input)
        {
            Description = description;
        }

        public event EventHandler CommandExecutionStatusChanged;

        public void OnCommandExecutionStatusChanged(EventArgs e)
        {
            var handler = CommandExecutionStatusChanged;
            if (handler != null) handler(this, e);
        }


        /// <summary>
        /// Does this instance.
        /// </summary>
        public abstract void Do(CommandParameter parameter);

        /// <summary>
        /// Undoes this instance.
        /// The Done flag have to be set in the overrides. It ought to always the case (after a undo, the action is undone)
        /// </summary>
        public abstract void Undo();

        /// <summary>
        /// Redoes this instance.
        /// Use the saved parameters, with some changement if necessary
        /// </summary>
        public abstract void Redo();

        private bool _done;

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="CommandGeneric"/> is done.
        /// </summary>
        /// <value>
        ///   <c>true</c> if done; otherwise, <c>false</c>.
        /// </value>
        public bool Done
        {
            get { return _done; }
            set
            {
                if (value == _done)
                    return;
                _done = value;
                OnPropertyChanged("Done");
                OnCommandExecutionStatusChanged(null);
            }
        }

        /// <summary>
        /// Contains the parameter and the target for the command
        /// Gets or sets the parameter.
        /// </summary>
        /// <value>
        /// The parameter.
        /// </value>
        public virtual CommandParameter Parameter { get; set; }

        private String _description;

        /// <summary>
        /// Gets or sets the description.
        /// </summary>
        /// <value>
        /// The description.
        /// </value>
        public String Description
        {
            get { return _description; }
            set
            {
                if (value == _description) return;
                _description = value;
                OnPropertyChanged("Description");
            }
        }

        #region INotifyPropertyChanged Members

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion


        public virtual object Clone()
        {
            return MemberwiseClone();
        }
    }
}
